<template>
  <div class="un-table-setter">
    <el-divider direction="horizontal">表格配置</el-divider>

    <el-form-item
      v-if="!isDynamicTable"
      label="是否启用API"
      size="small"
      label-width="100px"
    >
      <el-switch
        :value="api.enable"
        :active-value="true"
        :inactive-value="false"
        @change="(val) => changeApi(val, 'enable')"
      >
      </el-switch>
    </el-form-item>
    <template v-if="api.enable">
      <div type="flex" class="switch-config-item">
        <label>接口地址</label>
        <el-input
          :value="api.url"
          :title="api.url"
          placeholder="请输入接口地址"
          clearable
          @input="(val) => changeApi(val, 'url')"
        >
          <el-select
            slot="prepend"
            :value="api.method"
            :style="{ width: '85px' }"
            @change="(val) => changeApi(val, 'method')"
          >
            <el-option label="get" value="get" />
            <el-option label="post" value="post" />
            <el-option label="put" value="put" />
            <el-option label="delete" value="delete" />
          </el-select>
        </el-input>
      </div>
      <div type="flex" class="switch-config-item">
        <label>数据位置</label>
        <el-input
          :value="api.dataPath"
          placeholder="请输入数据位置"
          @input="(val) => changeApi(val, 'url')"
        />
      </div>
    </template>

    <el-form-item label="对齐方式" size="small">
      <el-radio-group v-model="activeData.align" size="small">
        <el-radio-button label="left"> 居左 </el-radio-button>
        <el-radio-button label="center"> 居中 </el-radio-button>
        <el-radio-button label="right"> 居右 </el-radio-button>
      </el-radio-group>
    </el-form-item>
    <el-form-item label="尺寸" size="small">
      <el-radio-group v-model="activeData.size">
        <el-radio-button label="medium"> 中等 </el-radio-button>
        <el-radio-button label="small"> 较小 </el-radio-button>
        <el-radio-button label="mini"> 迷你 </el-radio-button>
      </el-radio-group>
    </el-form-item>
    <el-form-item label="边框" size="small">
      <el-switch v-model="activeData.border"></el-switch>
    </el-form-item>
    <el-form-item
      v-if="!isDynamicTable"
      label="是否可编辑"
      size="small"
      label-width="100px"
    >
      <el-switch v-model="currEditConfig.enabled"></el-switch>
    </el-form-item>
    <template v-if="!isDynamicTable && currEditConfig.enabled">
      <div type="flex" class="switch-config-item">
        <label>触发方式</label>
        <el-radio-group v-model="currEditConfig.trigger" size="mini">
          <el-radio-button label="click"> 单击 </el-radio-button>
          <el-radio-button label="dbclick"> 双击 </el-radio-button>
        </el-radio-group>
      </div>
      <div type="flex" class="switch-config-item">
        <label>编辑模式</label>
        <el-radio-group v-model="currEditConfig.mode" size="mini">
          <el-radio-button label="row"> 按行编辑 </el-radio-button>
          <el-radio-button label="cell"> 按单元格编辑 </el-radio-button>
        </el-radio-group>
      </div>
    </template>
    <el-form-item label="编辑图标显示" size="small" label-width="100px">
      <el-switch v-model="currEditConfig.showIcon"></el-switch>
    </el-form-item>

    <el-divider direction="horizontal">表格列配置</el-divider>
    <el-form-item v-if="!isDynamicTable" label="首列设置" size="small">
      <div style="display: flex">
        <span
          class="select-line-icon"
          v-show="firstCol.type"
          @click="editColumn(firstCol, { colType: 'firstCol' })"
        >
          <i class="el-icon-edit" />
        </span>
        <el-select
          :value="firstCol.type"
          placeholder="首列类型"
          clearable
          size="mini"
          @change="(val) => changeFirstCol(val, 'type')"
        >
          <el-option value="" label="无"></el-option>
          <el-option value="seq" label="序号列"></el-option>
          <el-option value="checkbox" label="多选列"></el-option>
          <el-option value="radio" label="单选列"></el-option>
          <!-- <el-option value="expand" label="展开列"></el-option> -->
        </el-select>
        <el-input
          :value="firstCol.title"
          placeholder="列标题"
          size="mini"
          @input="(val) => changeFirstCol(val, 'title')"
        />
      </div>
    </el-form-item>

    <el-tree
      ref="tree"
      :data="columns"
      node-key="colId"
      empty-text="请配置表格列"
      highlight-current
      default-expand-all
      :expand-on-click-node="false"
      class="column-tree"
    >
      <template v-slot="{ node, data }">
        <span class="column-tree-node">
          <span class="column-tree-title">
            <span class="select-line-icon" @click="editColumn(data, { node })">
              <i class="el-icon-edit" />
            </span>
            <el-input v-model="data.title" placeholder="列标题" size="mini" />
            <el-input
              v-if="!isDynamicTable"
              v-model="data.field"
              placeholder="列字段名"
              size="mini"
            />
          </span>
          <span class="column-tree-oper">
            <el-button
              type="text"
              icon="el-icon-circle-plus-outline"
              @click="() => appendColumnChild(node, data)"
            >
            </el-button>
            <el-button
              type="text"
              icon="el-icon-remove-outline"
              @click="() => removeColumn(node, data)"
            >
            </el-button>
          </span>
        </span>
      </template>
    </el-tree>

    <el-button
      style="margin-left: 20px; padding-bottom: 0"
      icon="el-icon-circle-plus-outline"
      type="text"
      @click="addCol"
      >添加表格数据列
    </el-button>

    <el-divider direction="horizontal">单元格配置</el-divider>
    <el-form-item label="合并单元格" size="small">
      <el-select v-model="activeData.mergeType" @change="onMergeTypeChange">
        <el-option label="不合并" value="" />
        <el-option
          label="按行合并（同一列中，值相同的相邻行合并）"
          value="row"
        />
        <el-option label="自定义行列合并" value="handle" />
      </el-select>
      <el-select
        v-if="activeData.mergeType === 'row'"
        multiple
        v-model="activeData.rowMergedColFields"
        placeholder="请选择进行行合并的列"
        style="margin-top: 10px"
      >
        <el-option
          v-for="col in columnsFlatted"
          :key="col.colId"
          :label="col.title"
          :value="col.field"
        />
      </el-select>
      <el-button
        v-if="activeData.mergeType === 'handle'"
        type="text"
        size="small"
        icon="el-icon-edit"
        @click="showCellMergeDialog = true"
        >编辑自定义行列合并信息</el-button
      >
    </el-form-item>

    <el-dialog
      title="表格列设置"
      :visible.sync="showEditDialog"
      width="700px"
      @close="showEditDialog = false"
    >
      <el-descriptions
        class="edit-column-desc"
        title="基础配置"
        :column="2"
        border
      >
        <el-descriptions-item label="列标题">
          <el-input
            v-model="currEditCol.title"
            placeholder="请输入列标题"
            size="small"
            clearable
          ></el-input>
        </el-descriptions-item>
        <el-descriptions-item
          v-if="!(isDynamicTable || notChangeCols.includes(currEditColType))"
          label="列字段名"
        >
          <el-input
            v-model="currEditCol.field"
            placeholder="请输入列字段名"
            size="small"
            clearable
          ></el-input>
        </el-descriptions-item>
        <el-descriptions-item label="宽度">
          <el-input
            :value="currEditCol.width"
            placeholder="请输入，数字或者百分值%"
            size="small"
            clearable
            @input="(val) => onWidthChange(val, 'width')"
          ></el-input>
        </el-descriptions-item>
        <el-descriptions-item label="最小宽度">
          <el-input
            :value="currEditCol.minWidth"
            placeholder="请输入，数字或者百分值%"
            size="small"
            clearable
            @input="(val) => onWidthChange(val, 'minWidth')"
          ></el-input>
        </el-descriptions-item>
        <el-descriptions-item label="最大宽度">
          <el-input
            :value="currEditCol.maxWidth"
            placeholder="请输入，数字或者百分值%"
            size="small"
            clearable
            @input="(val) => onWidthChange(val, 'maxWidth')"
          ></el-input>
        </el-descriptions-item>
        <el-descriptions-item label="默认是否显示">
          <el-switch v-model="currEditCol.visible"></el-switch>
        </el-descriptions-item>
        <el-descriptions-item label="列固定位置">
          <el-radio-group v-model="currEditCol.fixed" size="small">
            <el-radio-button label=""> 不固定 </el-radio-button>
            <el-radio-button label="left"> 左侧 </el-radio-button>
            <el-radio-button label="right"> 右侧 </el-radio-button>
          </el-radio-group>
        </el-descriptions-item>
        <el-descriptions-item label="列对齐方式" :span="3">
          <el-radio-group v-model="currEditCol.align" size="small">
            <el-radio-button label="left"> 居左 </el-radio-button>
            <el-radio-button label="center"> 居中 </el-radio-button>
            <el-radio-button label="right"> 居右 </el-radio-button>
          </el-radio-group>
        </el-descriptions-item>
        <el-descriptions-item label="内容过长" :span="3">
          <el-radio-group v-model="currEditCol.showOverflow" size="small">
            <el-radio-button :label="false"> 显示完整 </el-radio-button>
            <el-radio-button label="tooltip"> 省略并悬浮提示 </el-radio-button>
          </el-radio-group>
        </el-descriptions-item>
      </el-descriptions>
      <el-descriptions
        v-if="currEditConfig.enabled"
        class="edit-column-desc"
        title="编辑配置"
        :column="2"
        border
      >
        <el-descriptions-item label="是否可编辑">
          <el-switch v-model="currEditCol.editRender.enabled"></el-switch>
        </el-descriptions-item>
        <el-descriptions-item v-if="!isDynamicTable" label="编辑方式">
          <el-select
            v-model="currEditCol.editRender.componentName"
            :disabled="!currEditCol.editRender.enabled"
            placeholder="请选择"
          >
            <el-option label="单行文本" value="el-input" />
            <el-option label="多行文本" value="el-textarea" />
            <!-- <el-option label="选择框(el-select)" value="el-select" /> -->
          </el-select>
        </el-descriptions-item>
      </el-descriptions>
      <span slot="footer">
        <el-button type="primary" @click="confirmColConfig">确认</el-button>
      </span>
    </el-dialog>

    <el-dialog
      title="自定义行列合并"
      :visible.sync="showCellMergeDialog"
      width="700px"
    >
      <el-alert
        title="注意"
        type="error"
        effect="light"
        closable
        class="merge-alert"
        >合并数据属于临时行为，操作数据源、显示隐藏列、固定列等操作都会导致合并状态被取消。
        <br />请完成上述操作后，再进行“自定义行列合并。
      </el-alert>

      <div
        v-for="(item, index) in mergeCells"
        :key="index"
        class="merge-item"
        style="margin: 10px 0"
      >
        <span>第</span>
        <el-input-number
          v-model="item.rowNum"
          :min="1"
          :max="rowSize"
          placeholder="请输入行号"
          controls-position="right"
        />
        <span>行，第</span>
        <el-input-number
          v-model="item.colNum"
          :min="1"
          :max="colSize"
          placeholder="请输入列号"
          controls-position="right"
        />
        <span>列，向右合并</span>
        <el-input-number
          v-model="item.right"
          :min="0"
          :disabled="colSize - item.colNum <= 0"
          :max="colSize - item.colNum"
          placeholder="请输入向右合并几列"
          controls-position="right"
        />
        <span>列，向下合并</span>
        <el-input-number
          v-model="item.bottom"
          :min="0"
          :disabled="rowSize - item.rowNum <= 0"
          :max="rowSize - item.rowNum"
          placeholder="请输入向下合并几行"
          controls-position="right"
        />
        <span>行</span>
        <div
          class="close-btn select-line-icon"
          @click="mergeCells.splice(index, 1)"
        >
          <i class="el-icon-remove-outline" />
        </div>
      </div>
      <el-button
        style="margin-left: 20px; padding-bottom: 0"
        icon="el-icon-circle-plus-outline"
        type="text"
        @click="
          mergeCells.push({
            rowNum: 1,
            colNum: 1,
            right: 0,
            bottom: 0,
          })
        "
        >添加自定义合并行列
      </el-button>
      <span slot="footer">
        <el-button type="primary" @click="confirmMerge">确认</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import draggable from "vuedraggable";
import { isNumberStr } from "@/utils/index";
import get from "lodash/get";
import defaultsDeep from "lodash/defaultsDeep";
// import isEqual from "lodash/isEqual";
import {
  getDefaultApi,
  getDefaultColumnProps,
  getDefaultColumnEditRender,
} from "./config";

export default {
  name: "UnTableSetter",
  components: {
    draggable,
  },
  props: {
    activeData: Object,
    // 默认的列配置，增加列的时候使用
    defaultColumn: {
      type: Object,
      default() {
        return getDefaultColumnProps();
      },
    },
    // 默认的列编辑配置，编辑列时使用
    defaultColEditRender: {
      type: Object,
      default() {
        return getDefaultColumnEditRender();
      },
    },
    /**
     * 表格类型：
     * 1： dynamic-table 动态表格：不需要接口；不变更字段field
     */
    tableType: {
      type: String,
      validator(val) {
        return ["", "dynamic-table"].includes(val);
      },
    },
  },
  data() {
    return {
      columns: [],
      columnsFlatted: [], // 扁平化的列数据
      showEditDialog: false,
      currEditCol: {
        editRender: { ...this.defaultColEditRender },
      }, // 当前编辑的列配置
      // currEditColIdx: -1, // 当前编辑的列配置序号
      currEditColNode: null, // 当前编辑的列配置节点
      currEditColType: "", // 当前操作列的类型：'' - 普通数据列; 'firstCol' - 首列；'actionsCol' - 操作列
      notChangeCols: ["firstCol", "actionsCol"], // 有些不能变更配置的列
      // 自定义行列合并单元格
      showCellMergeDialog: false,
      mergeCells: [],
      // 表格编辑操作

      currEditConfig: {
        enabled: false,
        trigger: "click",
        mode: "row", // 按行编辑
        showIcon: true,
        ...(this.activeData.editConfig ? this.activeData.editConfig : {}),
      },
    };
  },
  computed: {
    currValue() {
      return this.activeData.__config__.defaultValue;
    },
    api() {
      return this.activeData.api || getDefaultApi();
    },
    colSize() {
      return this.currValue && this.currValue.colSize;
    },
    rowSize() {
      return this.currValue && this.currValue.rowSize;
    },
    isDynamicTable() {
      return this.tableType === "dynamic-table";
    },
    firstCol() {
      return (
        this.activeData.firstCol ||
        defaultsDeep(
          { type: "", title: "", width: 50 },
          { ...this.defaultColumn }
        )
      );
    },
  },
  created() {
    this.init();
  },
  watch: {
    // 切换同类型组件时
    "activeData.__config__.renderKey": {
      handler(val) {
        this.$nextTick(() => {
          this.init();
        });
      },
    },
    currValue(val) {
      if (!!get(val, "columns.length", 0)) {
        this.columns = val.columns;
      }
    },
    columns: {
      handler(val) {
        this.$set(this.activeData.__config__.defaultValue, "columns", val);

        this.setFlattenColumns();
        // 列的个数，以叶子结点为准
        this.$set(
          this.activeData.__config__.defaultValue,
          "colSize",
          this.columnsFlatted.length
        );
      },
      deep: true,
    },

    currEditConfig: {
      handler(val) {
        this.$set(this.activeData, "editConfig", val);
      },
      deep: true,
    },
  },
  methods: {
    init() {
      if (!!get(this.currValue, "columns.length", 0)) {
        this.columns = this.currValue.columns;
      }
      if (!!get(this.activeData, "mergeCells.length", 0)) {
        this.mergeCells = this.activeData.mergeCells.map(
          ({ row, col, rowspan, colspan }) => ({
            rowNum: row + 1,
            colNum: col + 1,
            right: colspan - 1,
            bottom: rowspan - 1,
          })
        );
      }
      // 编辑初始化
      this.currEditConfig.enabled =
        this.activeData.editConfig &&
        this.activeData.editConfig.enabled !== false;

      this.setFlattenColumns();
    },
    setFlattenColumns() {
      // 扁平化列，用于合并列时选择
      const columnsFlatted = [];
      this.flattenColumns(this.columns, columnsFlatted);
      this.columnsFlatted = columnsFlatted;
    },
    // 扁平化列，只包含叶子结点
    flattenColumns(columns, columnsFlatted) {
      for (let i = 0; i < columns.length; i++) {
        const col = columns[i];
        if (col.children && col.children.length) {
          this.flattenColumns(col.children, columnsFlatted);
        } else {
          columnsFlatted.push(col);
        }
      }
    },
    getColId(col, defaultVal) {
      return col.colId || (col.field ? `col_${col.field}` : defaultVal);
    },
    // 利用查找的 colId ，来更新列表配置项
    updateColumns() {
      const colIds = [];
      let parent = this.currEditColNode;
      // 向上查找他的父节点，记录所有 colId
      while (parent.parent) {
        colIds.push(parent.data.colId);
        parent = parent.parent;
      }
      let currColId = colIds.pop();
      let currColIdx = -1;
      let currCols = this.columns;
      do {
        currColIdx = currCols.findIndex(({ colId }) => currColId === colId);
        // 是否有子列，无子列则结束查找
        currColId = colIds.pop();
        if (
          currColId &&
          currCols[currColIdx] &&
          currCols[currColIdx].children
        ) {
          currCols = currCols[currColIdx].children;
        }
      } while (currColId);
      this.$set(currCols, currColIdx, this.currEditCol);
    },
    editColumn(col, { node, colType }) {
      console.log("node", node);
      // this.currEditColIdx = idx;
      let colId = "";
      if (colType == "firstCol") {
        this.currEditColType = colType;
        colId = this.getColId(col, `col_${colType}`);
      } else {
        this.currEditColNode = node;
        // 兼容旧数据，没有colId，使用 el-tree 生成的 id
        colId = this.getColId(col, `col_${node?.id}`);
      }

      this.currEditCol = defaultsDeep(
        { ...col, colId },
        { ...this.defaultColumn, editRender: { ...this.defaultColEditRender } }
      );
      this.showEditDialog = true;
    },
    confirmColConfig() {
      if (this.currEditColType == "firstCol") {
        // 更新首列
        this.$set(this.activeData, "firstCol", this.currEditCol);
      } else if (this.currEditColType == "actionsCol") {
        // TODO 操作列更新
      } else {
        // 普通数据列的更新（可能多级表头，需要查找子树）
        this.updateColumns();
      }
      this.showEditDialog = false;
    },

    /* 增加一级列 */
    addCol() {
      const newChild = this.getDefaultCol(`col_root_${Date.now()}`);
      this.columns.push(newChild);
    },
    // API配置变更
    changeApi(val, key) {
      if (!this.activeData.api) {
        this.$set(this.activeData, "api", {
          ...this.api,
          [key]: val,
        });
      } else {
        this.$set(this.activeData.api, key, val);
      }
    },
    /* fetchData(val, key) {
      this.changeApi(val, key);
      this.$emit("fetch-data", this.activeData);
    }, */

    onWidthChange(val, key = "width") {
      this.currEditCol[key] = isNumberStr(val) ? +val : val;
    },
    onMergeTypeChange(val) {
      if (val === "handle") {
        this.showCellMergeDialog = true;
      } else {
        if (val == "row") {
          this.$set(this.activeData, "rowMergedColFields", []);
        }
        this.mergeCells = [];
        this.confirmMerge();
      }
    },
    confirmMerge() {
      const mergeCells = [];
      this.mergeCells.forEach(({ rowNum, colNum, right, bottom }) => {
        if (rowNum > 0 && colNum > 0) {
          mergeCells.push({
            row: rowNum - 1,
            col: colNum - 1,
            colspan: right + 1,
            rowspan: bottom + 1,
          });
        }
      });

      this.$set(
        this.activeData,
        "mergeCells",
        mergeCells.length ? mergeCells : undefined
      );
      this.showCellMergeDialog = false;
    },

    /* 多级表头配置 */
    getDefaultCol(field) {
      return defaultsDeep(
        {
          title: "",
          colId: field, // 唯一标志
          field, // 可编辑，可能为空，为空列可能有多个
        },
        { ...this.defaultColumn }
      );
    },
    // 增加子列，多级表头配置
    appendColumnChild(node, data) {
      if (!data.children) {
        this.$set(data, "children", []);
      }
      const colId = this.getColId(data, `col_${node.id}`);
      const field = colId + "_" + data.children.length;
      const newChild = this.getDefaultCol(field);
      data.children.push(newChild);
    },
    removeColumn(node, data) {
      const { parent } = node;
      const children = parent.data.children || parent.data;
      const index = children.findIndex(
        (d) => d.colId == data.colId && d.field == data.field
      );
      children.splice(index, 1);
    },

    /* 特殊列设置：首列、操作列等 */
    changeFirstCol(val, key) {
      if (!this.activeData.firstCol) {
        this.$set(this.activeData, "firstCol", {
          ...this.firstCol,
          [key]: val,
        });
      } else {
        this.$set(this.activeData.firstCol, key, val);
      }
    },
  },
};
</script>

<style lang="scss">
.un-table-setter {
  .switch-config-item {
    display: flex;
    align-items: center;
    text-align: right;
    margin-bottom: 10px;
    label:not(.el-radio-button) {
      min-width: 60px;
      margin-left: 20px;
      margin-right: 4px;
      color: #999999;
    }
  }
  .close-btn {
    cursor: pointer;
    color: #f56c6c;
  }
  .select-item {
    display: flex;
    border: 1px dashed #fff;
    box-sizing: border-box;
    display: flex;
    align-items: center;

    & .el-input + .el-input {
      margin-left: 4px;
    }
  }
  .select-item + .select-item {
    margin-top: 4px;
  }
  .select-item.sortable-chosen {
    border: 1px dashed #409eff;
  }
  .select-line-icon {
    line-height: 32px;
    font-size: 22px;
    padding: 0 4px;
    color: #777;
  }
  .option-drag {
    cursor: move;
  }

  .edit-column-desc {
    + .edit-column-desc {
      margin-top: 20px;
    }
  }
  .column-tree-node {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 14px;
    padding-right: 8px;
  }
  .column-tree-title {
    min-width: 60%;
    flex: 1;
    display: flex;
    align-items: center;
  }
  .column-tree {
    height: auto;
    .el-tree-node__content {
      height: auto;
    }
  }

  .merge-item {
    margin: 10px 0;
    display: flex;
    align-items: center;

    .el-input-number--medium {
      width: 80px;
    }
    .el-input-number.is-controls-right .el-input__inner {
      padding: 10px 40px 10px 10px;
    }
  }
  .merge-alert {
    .el-alert__description {
      font-size: 14px;
    }
  }
}
</style>
